﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using BrokerBase.Lib.Client;
using System.Data;
using System.Threading;
using System.ServiceModel;
using System.Windows;
using WCFDynamicProxyLibrary.DynamicProxy;
using System.ServiceModel.Description;
using Broker.Comm;

namespace Broker.Model
{
    public class UpdateServer
    {
        public const string DATAUPDATE_SERVICE_NAME = "DataUpdateService";
        public const string LICENSE_SERVICE_NAME = "licenseService";

        private static App app = (App)Application.Current;

        private static volatile bool shouldStop;//如果线程检查到该变量为true 则终止。

        private const int MAX_LENGTH = 256 * 1024 * 1024;//256M的最大数据
        private const int SLEEP_TIME = 1000 * 60;//间隔5分钟连接一次服务器

        public static ISessionFactory HbmSessionFactory { get; set; }

        public static IList<string> ServerUrls { get; set; }

        private static Thread thread;

        public static void Start()
        {
            thread = new Thread(LoopWork);
            app.Exit += new ExitEventHandler(app_Exit);

            ISession sess = HbmSessionFactory.OpenSession();

            thread.Start();

        }

        public static void LoopWork()
        {
            DynamicProxy wcfProxy = null;

            bool isSuccess = false;

            DateTime workTime = DateTime.MinValue;//

            while (!shouldStop)
            {
                TimeSpan span = DateTime.Now.Subtract(workTime);
                //如果连接更新成功就间隔1个小时再连接服务器，否则间隔5分钟连接一次
                if ((!isSuccess && span.TotalMinutes > 5) || (isSuccess && span.TotalHours > 1))
                {
                    try
                    {
                        foreach (string url in ServerUrls)
                        {
                            wcfProxy = CreateDynamicProxy(url, LICENSE_SERVICE_NAME);
                            if (wcfProxy != null)
                                break;
                        }

                        if (wcfProxy != null)
                        {
                            //成功获取服务端数据，就间隔一个小时。
                            GetUpdateInfo(wcfProxy);
                            isSuccess = true;
                            workTime = DateTime.Now;
                            Thread.Sleep(SLEEP_TIME * 12);
                        }
                        else
                        {
                            //没有成功创建wcf服务，就等5分钟后再试
                            Thread.Sleep(SLEEP_TIME);
                            isSuccess = false;
                            workTime = DateTime.Now;
                        }

                    }
                    catch (Exception er)
                    {
                        //以后用log4net写道日志中
                        //Thread.Sleep(SLEEP_TIME);
                        isSuccess = false;
                        workTime = DateTime.Now;
                    }
                }
                Thread.Sleep(300);//休眠300毫秒
            }
        }
        /// <summary>
        /// 创建一个wcf服务
        /// </summary>
        /// <param name="urls">服务器地址</param>
        /// <param name="serviceName">服务名称</param>
        /// <returns></returns>
        public static DynamicProxy GetWCFServer(IEnumerable<string> urls, string serviceName,Action<string> callBack)
        {
            DynamicProxy dp = null;

            foreach (string url in urls)
            {
                if(!string.IsNullOrEmpty(url))
                {
                    if(callBack!=null)
                        callBack(url);

                    dp = CreateDynamicProxy(url, serviceName);

                    if (dp != null)
                        break;
                }
            }
            return dp;
        }

        public static DynamicProxy CreateDynamicProxy(string url, string serviceName)
        {
            try
            {
                DynamicProxyFactory serverFactory =null;
                ServiceEndpoint endPoint =null;

                url = url.TrimEnd("/".ToCharArray()) + "/" + serviceName + ".svc";

                serverFactory = new DynamicProxyFactory(url);
                endPoint = serverFactory.GetEndpoint("I" + serviceName);

                WSHttpBinding bind = endPoint.Binding as WSHttpBinding;
                WSHttpBinding b = new WSHttpBinding();

                bind.ReaderQuotas.MaxArrayLength = MAX_LENGTH;//设置最大可接受的数组
                bind.ReaderQuotas.MaxBytesPerRead = MAX_LENGTH;
                bind.ReaderQuotas.MaxStringContentLength = MAX_LENGTH;
                bind.ReaderQuotas.MaxDepth = 64;

                bind.MaxBufferPoolSize = MAX_LENGTH;
                bind.MaxReceivedMessageSize = MAX_LENGTH;

                bind.SendTimeout = new TimeSpan(0, 5, 0);

                bind.Security.Message.EstablishSecurityContext = false;

                DynamicProxy svrProxy = serverFactory.CreateProxy("I" + serviceName);

                return svrProxy;
            }
            catch (Exception er)//不在向外抛出错误，但要记录错误信息
            {
                //throw er;
                return null;
            }
        }

        public static void GetUpdateInfo(DynamicProxy proxy)
        {
            ISession sess = HbmSessionFactory.OpenSession();

            dynamic svr = proxy.ObjectInstance;

            RegistrantInfo regInfo = LicenseInfo.GetInstance().CreateRegistrantInfo();

            TerminalInfo terInfo = ClientUtil.CreateTerminalInfo();

            SysUser user = sess.CreateCriteria<SysUser>().UniqueResult<SysUser>();

            try
            {
                CheckUpdate(regInfo, terInfo, svr, sess);

                UpdateUserInviteCodeQty(regInfo, terInfo, user, svr, sess);

                UpdateScoreInfo(regInfo, terInfo, user, svr, sess);

                CheckServerProduct(regInfo, terInfo, svr, sess);

            }
            catch (Exception er)
            {
                throw er;
            }
            finally
            {
                proxy.Close();
                if (sess.IsOpen)
                    sess.Close();
            }
        }
        /// <summary>
        /// 更新用户的可用的邀请码
        /// </summary>
        /// <param name="svr"></param>
        /// <param name="sess"></param>
        private static void UpdateUserInviteCodeQty(RegistrantInfo regInfo, TerminalInfo terInfo, SysUser user, dynamic svr, ISession sess)
        {
            int inviteCodeQty = svr.GetInviteCodeQty(regInfo.GetData(), terInfo.GetData());

            if (inviteCodeQty != user.InvitedCodeQty)
            {
                user.InvitedCodeQty = inviteCodeQty;

                sess.SaveOrUpdate(user);
            }
        }
        /// <summary>
        /// 更新积分数据
        /// </summary>
        /// <param name="sess"></param>
        /// <param name="tx"></param>
        private static void UpdateScoreInfo(RegistrantInfo regInfo, TerminalInfo terInfo, SysUser user, dynamic svr, ISession sess)
        {
            long serverScoreMaxTs = svr.GetScoreRecordMaxTs(regInfo.GetData(), terInfo.GetData());
            long localScoreMaxTs = ScoreInfo.LoadMax(sess);

            ITransaction tx = null;

            if (localScoreMaxTs != serverScoreMaxTs)
            {
                IList<dynamic> list = svr.GetClientScoreInfos(regInfo.GetData(), terInfo.GetData());

                if (list != null)
                {
                    try
                    {
                        tx = sess.BeginTransaction();
                        IDbCommand cmd = sess.Connection.CreateCommand();
                        tx.Enlist(cmd);

                        cmd.CommandText = "delete from sys_ScoreInfo";
                        cmd.ExecuteNonQuery();

                        for (int i = 0; i < list.Count; i++)
                        {
                            ScoreInfo info = new ScoreInfo();
                            info.Id = i;
                            info.User = user;
                            info.Level = list[i].Level;
                            info.Qty = list[i].Qty;
                            info.Score = list[i].Score;
                            info.UpdateTime = list[i].UpdateTime;
                            info.Ts = list[i].Ts;

                            sess.SaveOrUpdate(info);
                        }
                        tx.Commit();
                    }
                    catch (Exception er)
                    {
                        if (tx.IsActive)
                            tx.Rollback();

                        throw er;
                    }
                }
            }
        }
        /// <summary>
        /// 检查是否有新的产品可以更新
        /// </summary>
        /// <param name="regInfo"></param>
        /// <param name="terInfo"></param>
        /// <param name="svr"></param>
        /// <param name="sess"></param>
        private static void CheckServerProduct(RegistrantInfo regInfo, TerminalInfo terInfo, dynamic svr, ISession sess)
        {
            UpdateInfo lastInfo = UpdateInfo.LoadLastUpdateInfo(sess);

            if (lastInfo.UpdateTime != null)
            {
                long serverProductMaxTs = svr.GetProductMaxTs(regInfo.GetData(), terInfo.GetData());

                long localProductMaxTs = sess.CreateSQLQuery("select max(LastTimeStamp) from System_TableUpdate where IsNeedUpdate=1").UniqueResult<long>();

                if (serverProductMaxTs > localProductMaxTs)
                {
                    UpdateInfo newInfo = new UpdateInfo();
                    newInfo.CheckTime = DateTime.Now;
                    newInfo.ServerTimeStamp = serverProductMaxTs;
                    newInfo.ClientTimeStamp = localProductMaxTs;

                    ITransaction tx = null;

                    try
                    {
                        tx = sess.BeginTransaction();
                        sess.SaveOrUpdate(newInfo);

                        tx.Commit();

                    }
                    catch (Exception ex)
                    {
                        tx.Rollback();
                        throw ex;
                    }

                }
            }
        }

        private void CheckUpdate(RegistrantInfo regInfo, TerminalInfo terInfo, dynamic svr, ISession sess)
        {
            long localProductMaxTs = sess.CreateSQLQuery("select max(LastTimeStamp) from System_TableUpdate where IsNeedUpdate=1").UniqueResult<long>();

            long localScoreRecordMaxTs = sess.CreateSQLQuery("select max(ts) from Score_ScoreRecord where IsNeedUpdate=1").UniqueResult<long>();

            string result = svr.GetClientInfo(regInfo.GetData(), terInfo.GetData(), localProductMaxTs, localScoreRecordMaxTs);

            ClientDataInfo cdi = Newtonsoft.Json.JsonConvert.DeserializeObject<ClientDataInfo>(result);

        }

        static void app_Exit(object sender, ExitEventArgs e)
        {
            //调用abort有问题，以后再修改！
            //thread.Abort();//主线程结束，循环访问服务器的线程也结束.
            shouldStop = true;//线程终止标志
        }
    }
}
